﻿
namespace VMWareLabWorkflowsDataContracts.VMWareLabDetailsDialogControls.ViewModel
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Input;

    using Microsoft.TeamFoundation.Build.Workflow.Activities;
    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.Lab.Workflow.Activities;
    using Microsoft.TeamFoundation.TestManagement.Client;
    using VMWareLabWorkflowsDataContracts.VMWareLabDetailsDialogControls.Commands;
    using VMWareLabWorkflowsDataContracts.VMWareLabDetailsDialogControls.DataContracts;

    public class TestDetailsViewModel : INotifyPropertyChanged
    {
        private readonly ITestManagementService testManagementService;
        private readonly string teamProjectName;
        private string testSpecString;
        private TestSpecDialog testSpecDialog;
        private string selectedTestSuites;

        public TestDetailsViewModel()
        {
            try
            {
                if (VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.TestParameters == null)
                {
                    VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.TestParameters = new RunTestDetails();
                }
                this.TestDetails = VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.TestParameters;

                if (VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.AutomatedTestSettings == null)
                {
                    VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.AutomatedTestSettings = new AutomatedTestSettings();
                }
                if (VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.AutomatedTestSettings.TestSpecList == null)
                {
                    VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.AutomatedTestSettings.TestSpecList = new TestSpecList();
                }
                this.AutomatedTestSettings = VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.AutomatedTestSettings;
                this.testSpecDialog = new TestSpecDialog();
                this.testSpecString = this.testSpecDialog.GetTestSpecString();

                this.RunAutomatedTests = VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.AutomatedTestSettings.RunAutomatedTests;
                this.GetVersion = VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.AutomatedTestSettings.GetVersion;
                this.BuildDeployFolder = VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.AutomatedTestSettings.BuildDeployFolder;

                this.EnvironmentDetails = VMWareWizardData.VMWareWizzardDataInstance.VMWareLabWorkflowDetails.EnvironmentDetails;
                this.teamProjectName = VMWareWizardData.VMWareWizzardDataInstance.BuildDefinition.TeamProject;
                TfsTeamProjectCollection tfs = VMWareWizardData.VMWareWizzardDataInstance.BuildDefinition.BuildServer.TeamProjectCollection;
                this.testManagementService = tfs.GetService<ITestManagementService>();
                this.GetTestData(this.teamProjectName, this.testManagementService);
                this.GetSelectedTestSuitesString();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error initializing test details!", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public RunTestDetails TestDetails { get; set; }
        public VMWareLabEnvironmentDetails EnvironmentDetails { get; set; }
        public List<ITestSuiteBase> TestSuites { get; set; }
        public List<ITestPlan> TestPlans { get; set; }
        public List<ITestSettings> TestSettings { get; set; }
        public List<ITestEnvironment> TestEnvironments { get; set; }
        public ITestConfigurationCollection TestConfigurations { get; set; }
        public AutomatedTestSettings AutomatedTestSettings { get; set; }
        public string GetVersion { get; set; }
        public bool RunAutomatedTests { get; set; }
        public string BuildDeployFolder { get; set; }

        public string SelectedTestSuites
        {
            get
            {
                return this.selectedTestSuites;
            }
            set
            {
                this.selectedTestSuites = value;
                this.OnPropertyChanged("SelectedTestSuites");
            }
        }
        
        public string TestSpecString
        {
            get
            {
                return this.testSpecString;
            }
            set
            {
                this.testSpecString = value;
                this.OnPropertyChanged("TestSpecString");
            }
        }

        /// <summary>
        /// Gets the selected test suites string.
        /// </summary>
        private void GetSelectedTestSuitesString()
        {
            try
            {
                if (this.TestPlans == null || this.TestPlans.Count <= 0)
                {
                }
                else
                {
                    var testPlan = this.TestPlans.FirstOrDefault(p => p.Id == this.TestDetails.TestPlanId);
                    if (testPlan != null)
                    {
                        this.TestSuites = this.GetTestSuites(this.teamProjectName, this.testManagementService, testPlan.Name);
                    }

                    if (this.TestSuites != null && this.TestSuites.Count > 0)
                    {
                        this.SelectedTestSuites = string.Empty;
                        foreach (
                            var staticTestSuite in
                                this.TestSuites.Where(
                                    staticTestSuite => this.TestDetails.TestSuiteIdList.Contains(staticTestSuite.Id)))
                        {
                            if (this.SelectedTestSuites.Length == 0)
                            {
                                this.SelectedTestSuites = staticTestSuite.Title;
                            }
                            else
                            {
                                this.SelectedTestSuites += ", " + staticTestSuite.Title;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, string.Format("Error GetSelectedTestSuitesString"), MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// Gets the test plans.
        /// </summary>
        /// <param name="teamProject">
        /// The team project.
        /// </param>
        /// <param name="testManagementService">
        /// The test management service.
        /// </param>
        private void GetTestData(string teamProject, ITestManagementService testManagementService)
        {
            var testProject = testManagementService.GetTeamProject(teamProject);
            this.TestPlans = testProject.TestPlans.Query("SELECT * FROM TestPlan").ToList();
            this.TestSettings = testProject.TestSettings.Query("Select * from TestSettings").ToList();
            this.TestEnvironments = testProject.TestEnvironments.Query().ToList();
            this.TestConfigurations = testProject.TestConfigurations.Query("Select * from TestConfiguration");
        }

        /// <summary>
        /// Gets the test suites.
        /// </summary>
        /// <param name="teamProject">The team project.</param>
        /// <param name="testManagementService">The test management service.</param>
        /// <param name="selectedTestPlan">The selected test plan.</param>
        /// <returns>
        /// List of ITestSuiteBase
        /// </returns>
        private List<ITestSuiteBase> GetTestSuites(string teamProject, ITestManagementService testManagementService, string selectedTestPlan)
        {
            try
            {
                var testProject = testManagementService.GetTeamProject(teamProject);
                var plan = testProject.TestPlans.Query("SELECT * FROM TestPlan").FirstOrDefault(tp => tp.Name == selectedTestPlan);
                var testSuites = new List<ITestSuiteBase>();
                if (plan != null && plan.RootSuite != null)
                {
                    testSuites.AddRange(GetTestSuiteRecursive(plan.RootSuite));
                }
                return testSuites;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, string.Format("Error getting test suites. Team project: {0}, Selected test plan: {1}", teamProject, selectedTestPlan), MessageBoxButton.OK, MessageBoxImage.Error);
                return null;
            }

        }

        /// <summary>
        /// Gets the test suite recursive.
        /// </summary>
        /// <param name="testSuites">The b.</param>
        /// <returns>IEnumerable of ITestSuiteBase</returns>
        private static IEnumerable<ITestSuiteBase> GetTestSuiteRecursive(IStaticTestSuite testSuites)
        {
            var result = new List<ITestSuiteBase>();
            var stack = new Stack<ITestSuiteBase>();
            stack.Push(testSuites);
            
            while (stack.Count > 0)
            {
                var suite = stack.Pop();

                result.Add(suite);
                if (suite.TestSuiteType != TestSuiteType.StaticTestSuite)
                {
                    continue;
                }
                foreach (var subSuite in ((IStaticTestSuite)suite).SubSuites)
                {
                    stack.Push(subSuite);
                }
            }
            return result;
        }

        /// <summary>
        /// Gets the test suites for test plan.
        /// </summary>
        /// <param name="testPlan">The test plan.</param>
        public void GetTestSuitesForTestPlan(string testPlan)
        {
            try
            {
                this.TestSuites = this.GetTestSuites(this.teamProjectName, this.testManagementService, testPlan);

                if (this.TestSuites != null && this.TestSuites.Count > 0)
                {
                    if (!this.TestDetails.TestSuiteIdList.Contains(this.TestSuites[0].Id))
                    {
                        this.SelectedTestSuites = this.TestSuites[0].Title;
                        this.TestDetails.TestSuiteIdList.Clear();
                        this.TestDetails.TestSuiteIdList.Add(this.TestSuites[0].Id);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, string.Format("Error getting test suites for test plan: {0}", testPlan), MessageBoxButton.OK, MessageBoxImage.Error);
            }

        }

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        #region Commands
        protected void OpenSelectTestSuitesExecute()
        {
            if (this.TestSuites == null)
            {
                MessageBox.Show("No test plan selected!", "Error initializing select test suites!", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            var selectTestSuitesViewModel = new SelectTestSuitesViewModel(this.TestSuites, this.TestDetails.TestSuiteIdList);
            var selectSuites = new SelectTestSuitesWindow(selectTestSuitesViewModel);
            selectSuites.ShowDialog();
            if (selectSuites.DialogResult.HasValue && selectSuites.DialogResult.Value)
            {
                this.TestDetails.TestSuiteIdList.Clear();
                this.SelectedTestSuites = string.Empty;
                foreach (var ts in selectTestSuitesViewModel.VmTestSuites)
                {
                    this.GetTestSuiteIdListRecursive(ts);
                }
            }
        }

        private void GetTestSuiteIdListRecursive(TestSuite testSuite)
        {
            if (testSuite.IsChecked && !this.TestDetails.TestSuiteIdList.Contains(testSuite.SuiteId))
            {
                this.TestDetails.TestSuiteIdList.Add(testSuite.SuiteId);
                if (this.SelectedTestSuites.Length == 0)
                {
                    this.SelectedTestSuites += testSuite.SuiteTitle;
                }
                else
                {
                    this.SelectedTestSuites += ", " + testSuite.SuiteTitle;
                }
            }

            if (testSuite.TestSuites == null)
            {
                return;
            }
            foreach (var ts in testSuite.TestSuites)
            {
                this.GetTestSuiteIdListRecursive(ts);
            }
        }

        protected bool CanOpenSelectTestSuitesExecute()
        {
            return true;
        }

        public ICommand OpenSelectTestSuites
        {
            get
            {
                return new RelayCommand(this.OpenSelectTestSuitesExecute, this.CanOpenSelectTestSuitesExecute);
            }
        }

        void SelectAutomatedTestsExecute()
        {
            if (this.testSpecDialog == null)
            {
                this.testSpecDialog = new TestSpecDialog();
            }
            this.testSpecDialog.ShowEditor();
            this.TestSpecString = this.testSpecDialog.GetTestSpecString();
        }

        bool CanSelectAutomatedTestsExecute()
        {
            return true;
        }

        /// <summary>
        /// Gets SelectAutomatedTests.
        /// </summary>
        public ICommand SelectAutomatedTests
        {
            get
            {
                return new RelayCommand(this.SelectAutomatedTestsExecute, this.CanSelectAutomatedTestsExecute);
            }
        }

        #endregion
    }
}
